package com.bluexmicro.example.page.pick.file

import android.Manifest
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.provider.Settings
import android.text.TextUtils
import android.util.Log
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.*
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.*
import androidx.compose.runtime.snapshots.SnapshotStateList
import androidx.compose.ui.Alignment
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.TextUnit
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.lifecycle.viewmodel.compose.viewModel
import com.bluexmicro.example.BuildConfig
import com.bluexmicro.example.R
import com.google.accompanist.permissions.ExperimentalPermissionsApi
import com.google.accompanist.permissions.rememberPermissionState
import kotlinx.coroutines.flow.StateFlow
import java.io.File
import java.math.BigInteger

enum class OtaTaskType(val key: String) {
    FIRMWARE("固件"), MATERIAL("素材"), ZIP("ZIP"), FACE("表盘"), DICT("单词本")
}

@OptIn(ExperimentalComposeUiApi::class)
@Composable
fun FilePicker(
    modifier: Modifier = Modifier,
    taskTypes: List<OtaTaskType> = listOf(OtaTaskType.FIRMWARE, OtaTaskType.MATERIAL),
    onClose: () -> Unit,
    onSelected: (file: File, address: BigInteger?) -> Unit
) {
    val viewModel = viewModel<FileViewModel>()
    val keyboardController = LocalSoftwareKeyboardController.current
    val folders = remember {
        viewModel.folders
    }
    val files = remember {
        viewModel.files
    }

    var address by remember {
        mutableStateOf("")
    }
    val selectedFile = viewModel.selectedFile.collectAsState()

    var type by remember {
        mutableStateOf(taskTypes[0])
    }
    LaunchedEffect(Unit) {
        viewModel.reloadCurrentFiles(type)
    }
    FilePermissionComposable(modifier = modifier, viewModel) {
        Box(
            modifier = Modifier
                .fillMaxWidth()
                .defaultMinSize(minHeight = 64.dp)
                .background(color = MaterialTheme.colorScheme.primary)
        ) {
            IconButton(
                onClick = onClose,
                modifier = Modifier.align(Alignment.CenterStart)
            ) {
                Icon(
                    painter = painterResource(R.drawable.ic_arrow_left),
                    null,
                    modifier = Modifier.size(24.dp),
                    tint = MaterialTheme.colorScheme.onPrimary
                )
            }
            TypeTab(currentType = type, taskTypes, modifier = Modifier.align(Alignment.Center)) {
                type = it
                viewModel.reloadCurrentFiles(type)
            }
        }
        FolderPicker(folders) {
            viewModel.pick(it)
        }
        Divider(
            modifier = Modifier
                .fillMaxWidth()
                .height(1.dp)
        )
        FileListView(files.value, viewModel.selectedFile, Modifier.weight(1f)) {
            viewModel.pick(it)
        }
        Divider(
            modifier = Modifier
                .fillMaxWidth()
                .height(1.dp)
        )
        if (OtaTaskType.MATERIAL == type) {
            HexSoftKeyboard(modifier = Modifier.padding(horizontal = 16.dp)) {
                address = it
            }
        }
        Button(
            onClick = {
                if (type == OtaTaskType.MATERIAL) {
                    val bigAddress = try {
                        BigInteger(address, 16)
                    } catch (e: Exception) {
                        null
                    }
                    if (bigAddress == null) {
                        onClose.invoke()
                    } else {
                        onSelected.invoke(viewModel.selectedFile.value!!, bigAddress)
                    }
                    keyboardController?.hide()
                } else {
                    onSelected.invoke(viewModel.selectedFile.value!!, null)
                }
                viewModel.resetSelect()
            },
            modifier = Modifier
                .fillMaxWidth()
                .padding(horizontal = 16.dp, vertical = 8.dp),
            shape = RoundedCornerShape(16.dp),
            colors = ButtonDefaults.buttonColors(backgroundColor = MaterialTheme.colorScheme.primary),
            elevation = null,
            enabled = checkBtnEnable(type, selectedFile.value, address)
        ) {
            Text(
                "选择",
                modifier = Modifier.padding(8.dp),
                color = MaterialTheme.colorScheme.onPrimary
            )
        }
    }
}

@OptIn(ExperimentalPermissionsApi::class)
@Composable
fun FilePermissionComposable(
    modifier: Modifier,
    viewModel: FileViewModel,
    content: @Composable ColumnScope.() -> Unit
) {
    val context = LocalContext.current
    val hasPermission = remember {
        viewModel.hasPermission
    }
    val launcher =
        rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) {
            viewModel.checkPermission(context)
        }
    val permissions = rememberPermissionState(Manifest.permission.READ_EXTERNAL_STORAGE)
    LaunchedEffect(hasPermission) {
        viewModel.checkPermission(context)
    }
    if (!hasPermission.value) {
        Column(
            modifier = Modifier
                .fillMaxSize()
                .padding(32.dp),
            horizontalAlignment = Alignment.CenterHorizontally,
        ) {
            Icon(
                painter = painterResource(R.drawable.ic_close),
                null,
                modifier = Modifier.size(96.dp),
                tint = Color.Unspecified
            )
            Text("请授权app获取文件的权限。")
            Button(onClick = {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
                    val uri = Uri.parse("package:${BuildConfig.APPLICATION_ID}")
                    val intent =
                        Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION, uri)
                    launcher.launch(intent)
                } else {
                    permissions.launchPermissionRequest()
                }
            }) {
                Text("授权")
            }
        }
    } else {
        Column(modifier = modifier, content = content)
    }
}

sealed class TabTextInfo(
    val fontSize: TextUnit,
    val color: Color,
    val weight: FontWeight
) {
    object Selected : TabTextInfo(18.sp, Color.White, FontWeight.Bold)
    object Normal : TabTextInfo(12.sp, Color.LightGray, FontWeight.Normal)
}

@Composable
fun TypeTab(
    currentType: OtaTaskType,
    types: List<OtaTaskType>,
    modifier: Modifier,
    onChanged: (type: OtaTaskType) -> Unit
) {

    Row(modifier = modifier) {

        for (type in types) {
            val info = if (type == currentType) TabTextInfo.Selected else TabTextInfo.Normal
            TextButton(onClick = {
                onChanged.invoke(type)
            }) {
                Text(
                    type.key,
                    fontSize = info.fontSize,
                    color = info.color,
                    fontWeight = info.weight
                )
            }
        }

    }
}

fun checkBtnEnable(type: OtaTaskType, file: File?, address: String): Boolean {
    return if (type == OtaTaskType.MATERIAL) {
        file != null && !TextUtils.isEmpty(address)
    } else {
        file != null
    }
}

@Composable
fun FolderPicker(ptahs: List<File>, onClick: (file: File) -> Unit) {
    Row(
        verticalAlignment = Alignment.CenterVertically,
        modifier = Modifier
            .fillMaxWidth()
            .background(Color(0xFFDFDFDE))
    ) {
        Icon(
            painter = painterResource(R.drawable.ic_user_folder),
            null,
            modifier = Modifier
                .padding(start = 16.dp)
                .size(24.dp),
            tint = Color.Unspecified
        )
        Text(" : ")
        LazyRow {
            itemsIndexed(items = ptahs) { _, item ->
                Row(
                    verticalAlignment = Alignment.CenterVertically
                ) {
                    Text(
                        item.displayName(),
                        fontSize = 13.sp,
                        modifier = Modifier
                            .wrapContentSize()
                            .clickable {
                                onClick.invoke(item)
                            }
                            .defaultMinSize(minWidth = 24.dp)
                            .padding(vertical = 12.dp, horizontal = 8.dp),
                        textAlign = TextAlign.Center,
                        color = Color.Gray
                    )
                    Text("/", color = Color.Gray)
                }
            }
        }
    }

}

@Composable
fun FileListView(
    files: List<File>,
    selectedFile: StateFlow<File?>,
    modifier: Modifier,
    onClick: (file: File) -> Unit
) {
    val currentSelected = selectedFile.collectAsState()
    LazyColumn(modifier) {
        itemsIndexed(items = files) { _, item ->
            FileItem(item, currentSelected.value, onClick)
            Divider(
                color = Color.LightGray, thickness = Dp.Hairline
            )
        }
    }
}

@Composable
fun FileItem(file: File, checkedFile: File?, onClick: (file: File) -> Unit) {
    val desc = if (file.isFile) {
        file.contentSize(LocalContext.current)
    } else {
        "${file.childCount()} items"
    }
    Row(
        modifier = Modifier
            .fillMaxWidth()
            .clickable {
                onClick.invoke(file)
            }
            .padding(16.dp),
        verticalAlignment = Alignment.CenterVertically
    ) {
        Icon(
            painter = painterResource(getIcon(file)),
            null,
            modifier = Modifier.size(32.dp),
            tint = Color.Unspecified
        )
        Spacer(modifier = Modifier.width(16.dp))
        Column(modifier = Modifier.weight(1f)) {
            Text(file.displayName(), fontSize = 13.sp, color = Color.DarkGray)
            Text(desc, fontSize = 10.sp, color = Color.LightGray)
        }
        if (file.isFile) {
            val checkRes =
                if (file == checkedFile) R.drawable.ic_file_checked else R.drawable.ic_file_uncheck
            Icon(
                painter = painterResource(checkRes),
                null,
                modifier = Modifier.size(24.dp),
                tint = Color.Unspecified
            )
        }
    }

}

@Composable
fun HexSoftKeyboard(modifier: Modifier, onChanged: (address: String) -> Unit) {
    val row1 = "01234567"
    val row2 = "89ABCDEF"
    var addressTxt by remember {
        mutableStateOf("")
    }
    Column(
        modifier = modifier
    ) {
        Spacer(modifier = Modifier.height(8.dp))
        OutlinedTextField(
            addressTxt,
            onValueChange = {

            },
            modifier = Modifier.fillMaxWidth(),
            readOnly = true,
            trailingIcon = {
                IconButton(onClick = {
                    if (addressTxt.isEmpty()) return@IconButton
                    addressTxt = addressTxt.substring(0, addressTxt.lastIndex)
                    onChanged.invoke(addressTxt)
                }) {
                    Icon(
                        painter = painterResource(id = R.drawable.ic_backspace),
                        null,
                        tint = Color.Black,
                        modifier = Modifier.size(24.dp)
                    )
                }
            })
        Spacer(modifier = Modifier.height(8.dp))
        Row {
            Spacer(modifier = Modifier.width(8.dp))
            for (c in row1) {
                OutlinedButton(
                    onClick = {
                        addressTxt += c
                        onChanged.invoke(addressTxt)
                    }, modifier = Modifier.weight(1f),
                    contentPadding = PaddingValues(0.dp)
                ) {
                    Text("$c", color = MaterialTheme.colorScheme.primary)
                }
                Spacer(modifier = Modifier.width(8.dp))
            }
        }
        Row {
            Spacer(modifier = Modifier.width(8.dp))
            for (c in row2) {
                OutlinedButton(
                    onClick = {
                        addressTxt += c
                        onChanged.invoke(addressTxt)
                    },
                    modifier = Modifier.weight(1f),
                    contentPadding = PaddingValues(0.dp)
                ) {
                    Text("$c", color = MaterialTheme.colorScheme.primary)
                }
                Spacer(modifier = Modifier.width(8.dp))
            }
        }
    }
}

/**
 * 获取对应图标资源
 */
private fun getIcon(file: File): Int {
    return if (!file.isFile) {
        val childFileCount = file.childCount()
        if (childFileCount == 0) {
            R.drawable.ic_folder_empty
        } else {
            R.drawable.ic_folder
        }
    } else {
        when (file.extension.lowercase()) {
            "bin", "zip","bxface","bxdict" -> {
                R.drawable.ic_ota_file
            }

            else -> {
                R.drawable.ic_file
            }
        }
    }
}